package com.hclc.config.handler;



import com.hclc.config.context.exception.AuthenticationException;
import com.hclc.config.handler.enums.EnumReturnValue;
import com.hclc.config.util.PrintStackTraceUtil;
import com.hclc.entity.model.result.ResultEntity;
import com.hclc.util.excption.ValidateException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.CredentialsException;
import org.springframework.beans.ConversionNotSupportedException;
import org.springframework.beans.TypeMismatchException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    //运行时异常
    @ExceptionHandler(RuntimeException.class)
    public ResultEntity runtimeExceptionHandler(RuntimeException ex) {
        return resultFormat(EnumReturnValue.S_SERVERERROR, ex);
    }

    //空指针异常
    @ExceptionHandler(NullPointerException.class)
    public ResultEntity nullPointerExceptionHandler(NullPointerException ex) {
        return resultFormat(EnumReturnValue.S_SERVERERROR, ex);
    }

    //类型转换异常
    @ExceptionHandler(ClassCastException.class)
    public ResultEntity classCastExceptionHandler(ClassCastException ex) {
        return resultFormat(EnumReturnValue.S_SERVERERROR, ex);
    }

    //IO异常
    @ExceptionHandler(IOException.class)
    public ResultEntity iOExceptionHandler(IOException ex) {
        return resultFormat(EnumReturnValue.S_SERVERERROR, ex);
    }

    //未知方法异常
    @ExceptionHandler(NoSuchMethodException.class)
    public ResultEntity noSuchMethodExceptionHandler(NoSuchMethodException ex) {
        return resultFormat(EnumReturnValue.S_SERVERERROR, ex);
    }

    //数组越界异常
    @ExceptionHandler(IndexOutOfBoundsException.class)
    public ResultEntity indexOutOfBoundsExceptionHandler(IndexOutOfBoundsException ex) {
        return resultFormat(EnumReturnValue.S_SERVERERROR, ex);
    }


    //404界异常
    @ExceptionHandler(NoHandlerFoundException.class)
    public ResultEntity noHandlerFoundException(NoHandlerFoundException ex) {
        return resultFormat(EnumReturnValue.S_NOTFOUND, ex);
    }


    //400错误
    @ExceptionHandler({HttpMessageNotReadableException.class})
    public ResultEntity requestNotReadable(HttpMessageNotReadableException ex) {
        return resultFormat(EnumReturnValue.S_JSONPARSE, ex);
    }

    //400错误
    @ExceptionHandler({TypeMismatchException.class})
    public ResultEntity requestTypeMismatch(TypeMismatchException ex) {
        return resultFormat(EnumReturnValue.S_SERVERERROR, ex);
    }


    //上传大小超出限制
    @ExceptionHandler({MaxUploadSizeExceededException.class})
    public ResultEntity requestMaxUploadSizeExceededRequest(MaxUploadSizeExceededException ex) {
        return resultFormat(EnumReturnValue.S_MAXZISE, ex);
    }

    //400错误
    @ExceptionHandler({MissingServletRequestParameterException.class})
    public ResultEntity requestMissingServletRequest(MissingServletRequestParameterException ex) {
        return resultFormat(EnumReturnValue.S_PARAMMISS, ex);
    }

    //405错误
    @ExceptionHandler({HttpRequestMethodNotSupportedException.class})
    public ResultEntity request405(HttpRequestMethodNotSupportedException ex) {
        return resultFormat(EnumReturnValue.S_NOTACCEPTED, ex);
    }

    //406错误
    @ExceptionHandler({HttpMediaTypeNotAcceptableException.class})
    public ResultEntity request406(HttpMediaTypeNotAcceptableException ex) {
        return resultFormat(EnumReturnValue.S_NOTACCEPTED, ex);
    }

    //500错误
    @ExceptionHandler({ConversionNotSupportedException.class, HttpMessageNotWritableException.class})
    public ResultEntity server500(RuntimeException ex) {
        return resultFormat(EnumReturnValue.S_SERVERERROR, ex);
    }

    //栈溢出
    @ExceptionHandler({StackOverflowError.class})
    public ResultEntity requestStackOverflow(StackOverflowError ex) {
        return resultFormat(EnumReturnValue.S_SERVERERROR, ex);
    }

    //方法参数类型不匹配
    @ExceptionHandler({MethodArgumentTypeMismatchException.class})
    public ResultEntity requestArgumentTypeMismatch(MethodArgumentTypeMismatchException ex) {
        return resultFormat(EnumReturnValue.S_ARGUMENT_TYPE_MISMATCH, ex);
    }

//    //没有权限
//    @ExceptionHandler({UnauthorizedException.class})
//    public ResultEntity unauthorizedException(UnauthorizedException e){
//        return resultFormat(EnumReturnValue.S_NOAUTH, e);
//    }

    // 获取登录状态失败
    @ExceptionHandler({AuthenticationException.class})
    public ResultEntity unauthorizedException(AuthenticationException e) {
        return resultFormat(EnumReturnValue.S_NO_LOGIN_AUTH, e);
    }

    // 获取登录密码错误失败
    @ExceptionHandler({CredentialsException.class})
    public ResultEntity unauthorizedException(CredentialsException e) {
        return resultFormat(EnumReturnValue.S_LOGIN_AUTH_FAIL, e);
    }




    //其他错误
    @ExceptionHandler({Exception.class})
    public ResultEntity exception(Exception ex) {
        return resultFormat(EnumReturnValue.S_SERVERERROR, ex);
    }


    private ResultEntity resultFormat(EnumReturnValue code, Throwable ex) {
        log.error(ex.getMessage(), ex);
        //开发使用
//        if(StringUtils.isNotBlank(ex.getMessage())){
//            return ResultEntity.ResultFail(ex.getMessage(), PrintStackTraceUtil.getTrace(ex));
//        }
        return ResultEntity.ResultFail(code.getMessage(), PrintStackTraceUtil.getTrace(ex));
    }

    /**
     * 参数校验异常
     *
     * @param e
     * @return com.order.utils.result.ResultEntity
     * @author yurj
     * @mail 1638234804@qq.com
     * @version 1.0
     * @date 2020-2-29 17:02
     */

    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public ResultEntity exceptionHandler(MethodArgumentNotValidException e) {
        BindingResult bindingResult = e.getBindingResult();
        StringBuilder errorMessage = new StringBuilder();
        for (FieldError fieldError : bindingResult.getFieldErrors()) {
            errorMessage.append(fieldError.getDefaultMessage());
            errorMessage.append("!");
            errorMessage.append("   ");
        }
        return ResultEntity.ResultFail(errorMessage.toString(), null);
    }

    /**
     * 校验异常
     *
     * @param e
     * @return AjaxResult
     * @author yurj
     * @mail 1638234804@qq.com
     * @version 1.0
     * @date 2020-3-16 15:36
     */

    @ExceptionHandler(value = BindException.class)
    public ResultEntity validationExceptionHandler(BindException e) {
        BindingResult bindingResult = e.getBindingResult();
        StringBuilder errorMessage = new StringBuilder();
        for (FieldError fieldError : bindingResult.getFieldErrors()) {
            errorMessage.append(fieldError.getDefaultMessage());
            errorMessage.append("!");
            errorMessage.append("   ");
        }
        return ResultEntity.ResultFail(errorMessage.toString(), null);
    }

    /**
     * 自定义校验异常
     *
     * @param e
     * @return AjaxResult
     * @author yurj
     * @mail 1638234804@qq.com
     * @version 1.0
     * @date 2020-2-29 17:03
     */

    @ExceptionHandler(value = ValidateException.class)
    public ResultEntity validationExceptionHandler(ValidateException e) {
        return ResultEntity.ResultFail(e.getMessage(), e.getData());
    }

    /**
     * 校验异常
     *
     * @param ex
     * @return com.order.utils.result.ResultEntity
     * @author yurj
     * @mail 1638234804@qq.com
     * @version 1.0
     * @date 2020-2-29 17:03
     */

    @ExceptionHandler(value = ConstraintViolationException.class)
    public ResultEntity ConstraintViolationExceptionHandler(ConstraintViolationException ex) {
        Set<ConstraintViolation<?>> constraintViolations = ex.getConstraintViolations();
        Iterator<ConstraintViolation<?>> iterator = constraintViolations.iterator();
        List<String> msgList = new ArrayList<>();
        while (iterator.hasNext()) {
            ConstraintViolation<?> cvl = iterator.next();
            msgList.add(cvl.getMessageTemplate());
        }
        return ResultEntity.ResultFail(msgList.toString(), null);
    }


}
